<?php

/**
 * @Description    代码生成
 * @Author         zhaojiping
 * @Copyright      山东艾思软件科技有限公司(https://www.aisisofit.cn)
 * @Date           2022-6-15
 * @CreateBy       vs code
 */

namespace app\core\controller;

use app\core\model\CoreRule;
use think\facade\Db;
use think\facade\Env;
use think\facade\Config;

class CodeController extends \app\common\controller\CommonController {

    protected $database; // 数据库名称

    /**
     * 初始化
     */
    public function initialize() {
        parent::initialize();

        $this->database = Env::get('database.database');
    }

    public function showTables() {
        $result = Db::query("SHOW TABLE STATUS;");
        // p($result);
        foreach ($result as $k => &$v) {
            $tableName = $v['Name'];
            $arr = explode('_', $tableName);

            list($subAppName, $controllerName, $modelName, $validateName, $controllerPath, $modelPath, $validatePath)
                = $this->getNames($tableName);

            if ($arr[1] == 'core') {
                $v['can_edit'] = 0;
                $v['tab'] = 'system';
                $v['controller'] = $v['model'] = $v['validate'] = $v['vue'] = '系统';
            } else {

                $tableNameWithoutPre = $this->getTableNameWithoutPre($tableName, $ucfirst = false);
                $vuePath = Config::get('app.vue_path');
                if ($vuePath && !file_exists($vuePath)) $vuePath = 'vue';
                $vuePath = $vuePath . "/$subAppName/$tableNameWithoutPre/lists.vue";

                $v['controller'] = file_exists($controllerPath) ? '已存在' : '可生成';
                $v['model']      = file_exists($modelPath) ? '已存在' : '可生成';
                $v['validate']   = file_exists($validatePath) ? '已存在' : '可生成';
                $v['vue']        = file_exists($vuePath) ? '已存在' : '可生成';

                $can_edit = 1;
                if (
                    file_exists($controllerPath)
                    && file_exists($modelPath)
                    && file_exists($validatePath)
                    && file_exists($vuePath)
                ) $can_edit = 0;

                $v['can_edit'] = $can_edit;
                $v['tab'] = 'object';
            }
        }
        json_return(1, '表名列表', $result);
    }

    public function showColumns() {
        $tableName = input('table_name', '');
        if ($tableName == '') json_return(0, '未知错误: 参数丢失');
        $result = Db::query("SHOW FULL COLUMNS FROM `$tableName`");

        json_return(1, '列名列表', $result);
    }

    public function createCode() {

        $tableName = input('table_name', '');
        $tableComment = input('table_comment', '');

        if ($tableName == '') json_return(0, '未知错误: 参数丢失');

        function createFile($path, $code) {
            $file = fopen($path, 'w') or die("无法新建文件$path, 未知原因!");
            fwrite($file, $code);
            fclose($file);
        }

        list($subAppName, $controllerName, $modelName, $validateName, $controllerPath, $modelPath, $validatePath)
            = $this->getNames($tableName);

        // 去掉前缀的表名
        $tableNameWithoutPre = $this->getTableNameWithoutPre($tableName, $ucfirst = false);

        // 生成目录
        $vuePath = Config::get('app.vue_path');
        // p($vuePath);
        if (!file_exists($vuePath)) $vuePath = 'vue';
        if (!file_exists($vuePath)) mkdir($vuePath);
        $vuePath = $vuePath . "/$subAppName";
        if (!file_exists($vuePath)) mkdir($vuePath);
        $vuePath = $vuePath . "/$tableNameWithoutPre";
        if (!file_exists($vuePath)) mkdir($vuePath);

        $vuePath .= '/lists.vue';
        // 生成Vue
        if (!file_exists($vuePath)) {
            $vueCode = $this->getVueCode($tableName, $subAppName, $controllerName, $modelName, $validateName);
            createFile($vuePath, $vueCode);
        }

        // 生成目录 
        if (!file_exists("../app/$subAppName")) mkdir("../app/$subAppName");
        if (!file_exists("../app/$subAppName/controller")) mkdir("../app/$subAppName/controller");
        if (!file_exists("../app/$subAppName/model")) mkdir("../app/$subAppName/model");
        if (!file_exists("../app/$subAppName/validate")) mkdir("../app/$subAppName/validate");
        // 生成控制器
        if (!file_exists($controllerPath)) {
            $controllerCode = $this->getControllerCode($tableName, $subAppName, $controllerName, $modelName, $validateName);
            createFile($controllerPath, $controllerCode);
        }

        // 生成模型
        if (!file_exists($modelPath)) {
            $modelCode = $this->getModelCode($tableName, $subAppName, $controllerName, $modelName, $validateName);
            createFile($modelPath, $modelCode);
        }

        // 生成验证器
        if (!file_exists($validatePath)) {
            $validateCode = $this->getValidateCode($tableName, $subAppName, $controllerName, $modelName, $validateName);
            createFile($validatePath, $validateCode);
        }

        $ruleName = "/$subAppName/$tableNameWithoutPre/lists";
        $count = Db::name('CoreRule')->where('name', '=', $ruleName)->count();

        $tableComment = $tableComment != '' ? $tableComment : $tableNameWithoutPre;
        if ($count <= 0) {
            $data = [
                'pid'   => 334,
                'name'  => $ruleName,
                'title' => $tableComment . '管理',
                'icon'  => 'el-icon-document',
                'remark' => 'Curd系统生成'
            ];
            $id = CoreRule::insertGetId($data);

            $rules = Db::name('CoreRole')->where('id', '=', ROLE_ID)->value('rules');
            $data = [
                'rules' => $rules . ",$id",
            ];
            Db::name('CoreRole')->where('id', '=', ROLE_ID)->update($data);
        }

        json_return(1, '代码生成完成');
    }

    /**
     * 由原始表名生成去掉前缀后的表名, 并格式化
     * @param string $tableName : 原始表名
     * @param string $separator : 返回时去掉前缀后的表名是用什么符号分隔的, 如为空, 那首字母为大写
     * @return string 去掉前缀后的表名
     */
    private function getTableNameWithoutPre($tableName, $ucfirst = true) {
        $arr = explode('_', $tableName);
        $tableNameWithoutPre = '';
        for ($i = 2; $i < count($arr); $i++) {
            if ($ucfirst)
                $tableNameWithoutPre .= ucfirst($arr[$i]);
            else
                $tableNameWithoutPre .= $arr[$i] . '_';
        }
        return rtrim($tableNameWithoutPre, '_');
    }

    // 由表名得到类名等
    private function getNames($tableName) {
        $arr = explode('_', $tableName);

        $subAppName = $arr[1]; // 模块名
        // echo $subAppName . '<br/>';

        // 去掉前缀的表名, 并且首字母大写
        $tableNameWithoutPre = $this->getTableNameWithoutPre($tableName, $ucfirst = true);

        // 类名
        $controllerName = $tableNameWithoutPre . 'Controller'; // 控制器名称
        $modelName = $validateName = ucfirst($subAppName) . $tableNameWithoutPre;

        // 文件路径
        $controllerPath = "../app/{$subAppName}/controller/{$controllerName}.php";
        $modelPath = "../app/{$subAppName}/model/$modelName.php";
        $validatePath = "../app/{$subAppName}/validate/$validateName.php";

        return [$subAppName, $controllerName, $modelName, $validateName, $controllerPath, $modelPath, $validatePath];
    }

    // 生成vue代码
    private function getVueCode($tableName, $subAppName, $controllerName, $modelName, $validateName) {
        $tableNameWithoutPre = $this->getTableNameWithoutPre($tableName, $ucfirst = false);

        $result = Db::query("SHOW FULL COLUMNS FROM `$tableName`");
        $strForm = '';
        $strTableHeaderList = '';
        foreach ($result as $k => $v) {
            $field = $v['Field'];
            if ($field == 'create_time' || $field == 'update_time' || $field == 'id') continue;

            // 由备注得到标签名
            $comment = explode(' ', $v['Comment'])[0];
            $comment = explode(',', $comment)[0];
            $comment = explode('|', $comment)[0];
            $comment = $comment ? $comment : $field;

            // 得到类型
            $type = explode(' ', $v['Type'])[0];
            $type = explode('(', $type)[0];

            $strForm .= "                <el-form-item label='" . $comment . "'>
                    <el-input v-model='editForm." . $field . "'></el-input>
                </el-form-item>\n";

            if (
                $type == 'int'
                || $type == 'tinyint'
                || $type == 'smallint'
                || $type == 'mediumint'
                || $type == 'int'
                || $type == 'integer'
                || $type == 'bigint'
                || $type == 'datetime'
                || $type == 'date'
                || $type == 'float'
                || $type == 'double'
                || $type == 'decimal'
                || $type == 'numeric'
            )
                $strTableHeaderList .= "                { label: '$comment', value: '$field', align: 'right', sortable: true},\n";
            else
                $strTableHeaderList .= "                { label: '$comment', value: '$field', align: 'left', },\n";
        }

        return '<template>
    <div class="app-container">
        <custom-table-plus
            ref="table"
            :list="list"
            :total="total"
            :tableHeaderList="tableHeaderList"
            @fetch="$_fetch"
            @onBtnGroupAdd="$_onBtnGroupAdd"
            @onBtnGroupDelete="$_onBtnGroupDelete"
            @selection-change="$_handleSelectionChange"
            @customEditData="$_customEditData"
            @customDelete="$_customDelete"
        >
        </custom-table-plus>

        <custom-drag-dialog
            :show.sync="show"
            title="编辑"
            maxHeight="70vh"
            @confirm="$_dialogConfirm"
        >
            <el-form ref="form" :model="editForm" label-width="85px">
' . $strForm . '
            </el-form>
        </custom-drag-dialog>
    </div>
</template>

<script>
import request from "@/utils/request";
// 组件引入
import CustomTablePlus from "@/components/CustomTablePlus/index";
import CustomDragDialog from "@/components/CustomDragDialog/index";
// directives引入
import elDragDialog from "@/directive/el-drag-dialog";
// mixins 引入
import formMixin from "@/mixins/form/index";
import cacheMixin from "@/mixins/cache/index";
import tableMixin from "@/components/CustomTablePlus/mixins/index";
import dialogMixin from "@/components/CustomDragDialog/mixins/index";
export default {
    components: { CustomTablePlus, CustomDragDialog },
    directives: { elDragDialog },
    mixins: [formMixin, cacheMixin, tableMixin, dialogMixin],
    data() {
        return {
            editForm: {}, // 编辑表单数据

            tableHeaderList: [
                { label: "ID", value: "id", width: "120px", align: "right", sortable: true, },
' . $strTableHeaderList . '
                { label: "操作", value: "", width: "200px", custom: true, showDelete: true, showEdit: true, customName: "action", fixed: "right", },
            ],

            // formMixin 配置项
            requestFormOption: {
                debug: true,
                deleteUrl: "/' . $subAppName . '/' . $tableNameWithoutPre . '/del",
                editUrl: "/' . $subAppName . '/' . $tableNameWithoutPre . '/edit",
                fetchUrl: "/' . $subAppName . '/' . $tableNameWithoutPre . '/lists",
            },

            // formMixin 刷新项
            refresh: (p) => this.$refs.table.refresh(p),
        };
    },

    created() {
    },

    methods: {
    },
};
</script>
<style lang="scss" scoped>
</style>';
    }

    // 生成controller代码
    private function getControllerCode($tableName, $subAppName, $controllerName, $modelName, $validateName) {
        return '<?php

/**
 * @Description    控制器代码
 * @Author         ' . $this->user['username'] . '
 * @Copyright      山东艾思软件科技有限公司(https://www.aisisofit.cn)
 * @Date           ' . date('Y-m-d H:i:s') . '
 * @CreateBy       Curd System
 */

namespace app\\' . $subAppName . '\controller;

class ' . $controllerName . ' extends \app\common\controller\CommonController {
    protected $model = null;
    protected $validate = null;

    // 初始化
    public function initialize() {
        parent::initialize();

        $this->model = new \app\\' . $subAppName . '\model\\' . $modelName . '();
        $this->validate = new \app\\' . $subAppName . '\validate\\' . $validateName . '();
    }
}';
    }

    // 生成model代码
    private function getModelCode($tableName, $subAppName, $controllerName, $modelName, $validateName) {
        $result = Db::query("SHOW FULL COLUMNS FROM `$tableName`");
        $fields = '';
        $order = '';
        foreach ($result as $k => $v) {
            $fields .= $v['Field'] . ',';

            if ($v['Field'] == 'sort') $order .= 'sort, ';
            if ($v['Field'] == 'id') $order .= 'id, ';
            else if ($v['Field'] == 'create_time') $order .= 'create_time, ';
        }
        $fields = rtrim($fields, ',');
        $order = rtrim($order, ', ');

        return '<?php

/**
 * @Description    控制器代码
 * @Author         ' . $this->user['username'] . '
 * @Copyright      山东艾思软件科技有限公司(https://www.aisisofit.cn)
 * @Date           ' . date('Y-m-d H:i:s') . '
 * @CreateBy       Curd System
 */

namespace app\\' . $subAppName . '\model;

use think\facade\Db;

class ' . $modelName . ' extends \app\common\model\CommonModel {
    protected $fields = \'' . $fields . '\'; // 通用查询字段
    protected $order = \'' . $order . '\'; // 排序字段

    // 添加前的操作
    public static function onBeforeInsert($row) {
        parent::onBeforeInsert($row);
    }
    // 修改前的操作 
    public static function onBeforeUpdate($row) {
        parent::onBeforeUpdate($row);
    }

    // 删除前的操作
    public static function onBeforeDelete($row) {
        parent::onBeforeDelete($row);
    }

    // 读取后的操作
    public static function onAfterRead($row) {
        parent::onAfterRead($row);
    }
}';
    }

    // 生成model代码
    private function getValidateCode($tableName, $subAppName, $controllerName, $modelName, $validateName) {
        $result = Db::query("SHOW FULL COLUMNS FROM `$tableName`");
        $strRule = '';
        $strField = '';
        $strMessage = '';
        foreach ($result as $k => $v) {
            $field = $v['Field'];
            if ($field == 'create_time' || $field == 'update_time' || $field == 'id') continue;
            $type = explode(' ', $v['Type'])[0];
            $type = explode('(', $type)[0];

            if ($type == 'int' || $type == 'tinyint' || $type == 'smallint' || $type == 'mediumint' || $type == 'int' || $type == 'integer' || $type == 'bigint')
                $strType = 'integer|';
            else if ($type == 'datetime' || $type == 'date')
                $strType = 'date|';
            else if ($type == 'float' || $type == 'double' || $type == 'decimal' || $type == 'numeric')
                $strType = 'float|';
            else
                $strType = '';

            // 获取长度
            $result = array();
            preg_match_all("/(?:\()(.*)(?:\))/i", $v['Type'], $result);
            $strMax = '';
            if ($result[1]) $strMax = 'max:' . $result[1][0];

            $strCondition = rtrim($strType . $strMax, '|');
            $strRule .= "'{$field}' => '$strCondition',\n        ";

            $comment = explode(' ', $v['Comment'])[0];
            $comment = explode(',', $comment)[0];
            $comment = explode('|', $comment)[0];
            $comment = $comment ? $comment : $field;

            $strField .= "'{$field}' => '$comment',\n        ";

            if ($strCondition) {
                $arrCondition = explode('|', $strCondition);
                foreach ($arrCondition as $ke => $val) {
                    $arrVal = explode(':', $val);

                    $msg = '';
                    if ($val == 'integer') $msg = '必须是整数';
                    else if ($val == 'date') $msg = '必须是个日期或时间';
                    else if ($val == 'float') $msg = '必须是个浮点数';
                    else
                        if ($arrVal[1]) $msg = '超过最大长度' . $arrVal[1];

                    $strMessage .= "'$field.{$arrVal[0]}' => '{$comment}{$msg}',\n        ";
                }
            }
        }

        return
            '<?php

/**
 * @Description    验证器
 * @Author         ' . $this->user['username'] . '
 * @Copyright      山东艾思软件科技有限公司(https://www.aisisofit.cn)
 * @Date           ' . date('Y-m-d H:i:s') . '
 * @CreateBy       Curd System
 */

namespace app\\' . $subAppName . '\validate;

use think\Validate;

class ' . $validateName . ' extends Validate {

    // 定义验证规则
    protected $rule = [
        ' . $strRule . '
    ];

    // 定义验证字段名称
    protected $field = [
        ' . $strField . '
    ];

    // 定义验证返回信息
    protected $message = [
        ' . $strMessage . '
    ];
}';
    }
}
